home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume8 / qterm < prev    next >
Encoding:
Internet Message Format  |  1987-03-02  |  24.5 KB

  1. Subject:  v08i095:  Query terminal for its type
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: Michael A. Cooper <usc-oberon!mcooper>
  6. Mod.sources: Volume 8, Issue 95
  7. Archive-name: qterm
  8.  
  9. #!/bin/sh
  10. # This is a shell archive, meaning:
  11. # 1. Remove everything above the #!/bin/sh line.
  12. # 2. Save the resulting text in a file.
  13. # 3. Execute the file with /bin/sh (not csh) to create the files:
  14. #    README Makefile table.c qterm.c qterm.1
  15. # Wrapped by Michael A. Cooper (USC Computing Services, Los Angeles)
  16. export PATH; PATH=/bin:$PATH
  17. echo shar: extracting "'README'" '(936 characters)'
  18. if test -f 'README'
  19. then
  20.     echo shar: over-writing existing file "'README'"
  21. fi
  22. cat << \SHAR_EOF > 'README'
  23.  
  24.          Q T E R M  -  Q U E R Y   T E R M I N A L
  25.  
  26.                       Revision 1.23
  27.                  January, 1987
  28.  
  29.     Qterm is a program that queries terminals to find out what kind
  30. of terminal is responding.  It is useful to automagically define your
  31. terminal type.  It prints the name of the terminal (compatible, hopefully,
  32. with a termcap/terminfo name) such as "vt100" to standard output.
  33. See the manual for details.
  34.  
  35.     Qterm was written under 4.2BSD and will probably run without 
  36. modification on other Berkeley Unix systems.  It has been tested under
  37. 4.2BSD, 4.3BSD, Sun 3.0 and Sun 3.2.  It should work under System V.2,
  38. but I have not personally tested it on such a system.  (For System V.2,
  39. compile with USG5 defined).
  40.  
  41.  
  42.                 Mike
  43.  
  44.  
  45. Michael A. Cooper, University Computing Services, U of Southern California
  46.   UUCP: {sdcrdcf, uscvax}!usc-oberon!mcooper  BITNET: mcooper@uscvaxq
  47.   ARPA: mcooper@usc-oberon.USC.EDU            PHONE: (213) 743-3462
  48. SHAR_EOF
  49. echo shar: extracting "'Makefile'" '(449 characters)'
  50. if test -f 'Makefile'
  51. then
  52.     echo shar: over-writing existing file "'Makefile'"
  53. fi
  54. cat << \SHAR_EOF > 'Makefile'
  55. #
  56. # $Header: Makefile,v 1.1 86/12/22 10:45:46 mcooper Exp $
  57. #
  58. # Makefile for QTERM
  59. #
  60. BIN=/usr/usc/bin
  61. MAN=/usr/usc/man/man1
  62.  
  63. OBJS = qterm.o table.o
  64.  
  65. #
  66. # Use "-DUSG5" for $(CFLAGS) below, if your system is Unix System V.
  67. #
  68. CFLAGS = -O
  69.  
  70. qterm: $(OBJS)
  71.     cc $(CFLAGS) $(OBJS) -o qterm
  72.  
  73. shar:
  74.     shar README Makefile table.c qterm.c qterm.1 > qterm.shar
  75.  
  76. clean:
  77.     rm -f *.o core log 
  78.  
  79. install: qterm qterm.1
  80.     install qterm $(BIN)
  81.     install -c qterm.1 $(MAN)
  82. SHAR_EOF
  83. echo shar: extracting "'table.c'" '(2400 characters)'
  84. if test -f 'table.c'
  85. then
  86.     echo shar: over-writing existing file "'table.c'"
  87. fi
  88. cat << \SHAR_EOF > 'table.c'
  89. #ifndef lint
  90. static char *RCSid = "$Header: table.c,v 1.3 86/11/13 15:40:26 mcooper Locked $";
  91. #endif
  92.  
  93. /*
  94.  *------------------------------------------------------------------
  95.  *
  96.  * $Source: /big/mcooper/src/qterm/RCS/table.c,v $
  97.  * $Revision: 1.3 $
  98.  * $Date: 86/11/13 15:40:26 $
  99.  * $State: Exp $
  100.  * $Author: mcooper $
  101.  * $Locker: mcooper $
  102.  *
  103.  *------------------------------------------------------------------
  104.  *
  105.  * Michael A. Cooper
  106.  * University Computing Services, 
  107.  * University of Southern California
  108.  * (mcooper@usc-oberon.arpa)
  109.  *
  110.  *------------------------------------------------------------------
  111.  * $Log:    table.c,v $
  112.  * Revision 1.3  86/11/13  15:40:26  mcooper
  113.  * z29 -> h29.  "h29" is recognized
  114.  * more.
  115.  * 
  116.  * Revision 1.2  86/07/01  23:13:04  mcooper
  117.  * Added vt220 and f220 entries.
  118.  * 
  119.  * Revision 1.1  86/07/01  22:58:12  mcooper
  120.  * Initial revision
  121.  * 
  122.  *------------------------------------------------------------------
  123.  */
  124.  
  125. #include <stdio.h>
  126.  
  127. /*
  128.  * The Master Table
  129.  */
  130. char *terms[] = {
  131. /*  Terminal Sends:            Terminal Name:     Real Name:         */
  132. /*    ---------------            --------------     ----------         */
  133.     "\33[?1;0c",            "vt100",        "Base vt100",
  134.     "\33[?1;1c",            "vt100",        "vt100 with STP",
  135.     "\33[?1;2c",            "vt100",        "ANSI/VT100 Clone",
  136.     "\33[?1;3c",            "vt100",        "vt100 with AVO and STP",
  137.     "\33[?1;4c",            "vt100",        "vt100 with GPO",
  138.     "\33[?1;5c",            "vt100",        "vt100 with GPO and STP",
  139.     "\33[?1;6c",            "vt100",        "vt100 with GPO and AVO",
  140.     "\33[?1;7c",            "vt100",        "vt100 with GPO, STP, and AVO",
  141.     "\33[?6c",                "vt100",        "Generic vt100",
  142.     "\33[?8c",                "vt100",        "TeleVideo 970",
  143.     "\33[0n",                "vt100",        "AT&T Unix PC 7300",
  144.     "\33[?l;0c",            "vt100",        "AT&T Unix PC 7300",
  145.     "\33[?12c",                "vt100",        "Concept from Pro 350/UNIX",
  146.     "\33[?;c",                "vt100",        "Concept From Pro 350/UNIX",
  147.     "\33[=1;1c",            "avt-4p-s",        "Concept with 4 pages memory",
  148.     "\33[=1;2c",            "avt-8p-s",        "Concept with 8 pages memory",
  149.     "\33iBO",                "h29",            "Zenith z29 in zenith mode",
  150.     "\33/K",                "h29",            "Zenith z29 in zenith mode",
  151.     "\33/Z",                "vt52",            "Generic vt52",
  152.     "\33[?12;7;0;102c",        "vt125",        "DEC Pro 350 in vt125 mode",
  153.     "\33[?10c",                "la120",        "DEC Writer III",
  154.     "\33[?1;11c",            "cit101e",        "CIE CIT-101 Enhanced w/Graphics",
  155. /*    "\33[?1;11c",            "xt100+",        "Northern Tech LANPARSCOPE",    */
  156.     "\33[?62;1;2;6;7;8;9c",    "vt220",        "DEC VT220",
  157.     "\33[62;1;2;6;8c",        "f220",            "Freedom 220 DEC clone",
  158.     NULL
  159. };
  160. SHAR_EOF
  161. echo shar: extracting "'qterm.c'" '(16314 characters)'
  162. if test -f 'qterm.c'
  163. then
  164.     echo shar: over-writing existing file "'qterm.c'"
  165. fi
  166. cat << \SHAR_EOF > 'qterm.c'
  167. #ifndef lint
  168. static char *RCSid = "$Header: qterm.c,v 1.23 87/01/09 13:55:44 mcooper Locked $";
  169. #endif
  170.  
  171. /*
  172.  *------------------------------------------------------------------
  173.  *
  174.  * $Source: /big/src/usc/bin/qterm/RCS/qterm.c,v $
  175.  * $Revision: 1.23 $
  176.  * $Date: 87/01/09 13:55:44 $
  177.  * $State: Exp $
  178.  * $Author: mcooper $
  179.  * $Locker: mcooper $
  180.  *
  181.  *------------------------------------------------------------------
  182.  *
  183.  * Michael A. Cooper
  184.  * University Computing Services, 
  185.  * University of Southern California
  186.  * (mcooper@usc-oberon.arpa)
  187.  *
  188.  *------------------------------------------------------------------
  189.  * $Log:    qterm.c,v $
  190.  * Revision 1.23  87/01/09  13:55:44  mcooper
  191.  * Fixed bug with -s option that caused "ers:" 
  192.  * to be printed instead of the string
  193.  * received from the terminal.
  194.  * 
  195.  * Revision 1.22  86/12/11  15:57:16  mcooper
  196.  * Should now work under System V thanks to Brian L. Matthews
  197.  * (cxsea!blm).
  198.  * 
  199.  * Revision 1.21  86/10/13  12:52:54  mcooper
  200.  * Fixed bug that caused problems with
  201.  * send strings not being sent from .qterm
  202.  * files.
  203.  * 
  204.  * Revision 1.20  86/08/25  15:45:58  mcooper
  205.  * BUG FIX: When the -f flag was specified and the user's
  206.  *          tables did not produce the terminal's entry,
  207.  *          the internal terminal tables where not tried
  208.  *          as documented.
  209.  * 
  210.  * Revision 1.19  86/08/12  15:31:22  mcooper
  211.  * Fixed bug that caused terminals to wedge due
  212.  * to qterm failing to match receive strings
  213.  * from the .qterm file.
  214.  * 
  215.  * Revision 1.18  86/08/11  13:49:42  mcooper
  216.  * Fixed bug that caused qterm to wedge.  Problem
  217.  * due to alarms not being set correctly.
  218.  * 
  219.  * Revision 1.17  86/08/08  14:40:09  mcooper
  220.  * - Only send/listen for strings if the previously sent string
  221.  *   is not the same as the current string.
  222.  * - Fixed -s option.
  223.  * 
  224.  * Revision 1.16  86/08/08  13:16:05  mcooper
  225.  * Major re-write: Added ~/.qterm file that contains
  226.  * the users own copy of terminal tables.
  227.  * 
  228.  * Revision 1.15  86/07/21  12:35:54  mcooper
  229.  * Now works under System V (Define USG5).
  230.  * 
  231.  * Revision 1.14  86/07/01  22:57:45  mcooper
  232.  * Moved terminal table to seperate
  233.  * file (table.c).
  234.  * 
  235.  * Revision 1.13  86/06/30  11:17:53  mcooper
  236.  * More terminals to main table...
  237.  * 
  238.  * Revision 1.12  86/06/19  13:57:51  mcooper
  239.  * Added responses for concept from a Pro running
  240.  * 2.9bsd.
  241.  * 
  242.  * Revision 1.11  86/06/18  15:58:45  mcooper
  243.  * Cleanup for release.
  244.  * 
  245.  * Revision 1.10  86/06/17  23:06:55  mcooper
  246.  * Added Unix PC responses.
  247.  * 
  248.  * Revision 1.9  86/06/16  14:19:09  mcooper
  249.  * Added vt100 responses from vt100 manual.
  250.  * 
  251.  * Revision 1.8  86/06/16  13:23:40  mcooper
  252.  * Print additional information about
  253.  * what the actual terminal is.
  254.  * 
  255.  * Revision 1.7  86/06/12  10:59:27  mcooper
  256.  * *** empty log message ***
  257.  * 
  258.  * Revision 1.6  86/06/11  19:48:35  mcooper
  259.  * Added alternate string and table entries for concepts.
  260.  * 
  261.  * Revision 1.5  86/05/19  12:30:32  mcooper
  262.  * General clean up.
  263.  * 
  264.  * Revision 1.4  86/05/18  17:56:11  mcooper
  265.  * Added another vt100.  This one is for when you rlogin
  266.  * from a Pro 2.9bsd host on a HDS Concept.
  267.  * 
  268.  * Revision 1.3  86/05/08  09:24:13  mcooper
  269.  * Added another vt100 description.
  270.  * 
  271.  * Revision 1.2  86/05/06  18:23:35  mcooper
  272.  * More cleanup - de-linted (almost).
  273.  * 
  274.  * Revision 1.1  86/05/06  14:56:57  mcooper
  275.  * Initial revision
  276.  * 
  277.  *------------------------------------------------------------------
  278.  */
  279.  
  280. /*
  281.  * [Edit with tabstop=4]
  282.  *
  283.  * qterm - Query Terminal
  284.  *
  285.  * qterm is used to query a terminal to determine the name of the terminal.
  286.  * This is done by sending a fairly universal string "\33Z" to the terminal,
  287.  * reading in a response, and comparing it against a master table of responses
  288.  * and names.  The "name" printed to standard output should be one found in
  289.  * the termcap(5) database.
  290.  *
  291.  * Putting a line in your ".login" file such as:
  292.  *
  293.  *    setenv TERM `qterm`
  294.  *
  295.  * or the following lines in your ".profile" file:
  296.  *
  297.  *    TERM=`qterm`
  298.  *    export TERM
  299.  *
  300.  * will set your terminal type automagically.
  301.  * 
  302.  * If you add a terminal to the master table, please also send me a copy
  303.  * so that I may put it into my version.
  304.  *
  305.  * Michael Cooper
  306.  * ARPA:     mcooper@usc-oberon.ARPA
  307.  * UUCP:     mcooper@usc-oberon.UUCP
  308.  * BITNET:    mcooper@uscvaxq
  309.  */
  310.  
  311. #include <stdio.h>
  312. #include <pwd.h>
  313. #include <signal.h>
  314. #include <sys/ioctl.h>
  315. #include <setjmp.h>
  316. #ifdef USG5
  317. # include <termio.h>
  318. #else
  319. # include <sys/file.h>
  320. # include <sgtty.h>
  321. #endif
  322.  
  323. #define SEND        "\033Z"        /* send this to query terminal */
  324. #define ALTSEND        "\033[c"    /* alternate string */
  325.  
  326. #define STRFILE        ".qterm"    /* file containing terminal strings */
  327.  
  328. #define dprintf        if(debug)printf
  329. #define MAXTERMS    100
  330.  
  331. #define TRUE        1
  332. #define FALSE        0
  333.  
  334. #define T_STR        0
  335. #define T_NAME        1
  336. #define T_LNAME        2
  337.  
  338. int tabmark = 0;
  339. int tabtotal = 0;
  340. int has_set = 0;
  341.  
  342.  
  343. #define BUF            666
  344.  
  345. struct qt {
  346.     char    qt_sendstr[BUFSIZ];         /* String to send to terminal */
  347.     char    qt_recvstr[BUFSIZ];            /* String expected in response */
  348.     char    qt_termname[BUFSIZ];        /* Terminal name */
  349.     char    qt_fullname[BUFSIZ];        /* Full terminal name & description */
  350. };
  351. struct qt *compare();
  352. static struct qt termtab[MAXTERMS];
  353.  
  354.  
  355. #ifdef USG5
  356. struct termio _ntty, _otty;
  357. #else
  358. struct sgttyb _tty;
  359. #endif
  360. int _tty_ch = 2;
  361.  
  362. #ifdef USG5
  363. # define crmode()        (_ntty.c_lflag &= ~ICANON,\
  364.                          _ntty.c_cc[VMIN] = 1, _ntty.c_cc[VTIME] = 0,\
  365.                          ioctl(_tty_ch, TCSETAF, &_ntty))
  366. # define nocrmode()        (_ntty.c_lflag |= ICANON,\
  367.                          _ntty.c_cc[VMIN] = _otty.c_cc[VMIN],\
  368.                          _ntty.c_cc[VTIME] = _otty.c_cc[VTIME],\
  369.                          ioctl(_tty_ch, TCSETAF, &_ntty))
  370. # define echo()            (_ntty.c_lflag |= ECHO,\
  371.                          ioctl(_tty_ch, TCSETAF, &_ntty))
  372. # define noecho()        (_ntty.c_lflag &= ~ECHO,\
  373.                          ioctl(_tty_ch, TCSETAF, &_ntty))
  374. #else
  375. # define crmode()         (_tty.sg_flags |= CBREAK,\
  376.                             ioctl(_tty_ch, TIOCSETP, &_tty))
  377. # define nocrmode()     (_tty.sg_flags &= ~CBREAK,\
  378.                             ioctl(_tty_ch, TIOCSETP, &_tty))
  379. # define echo()         (_tty.sg_flags |= ECHO,   \
  380.                             ioctl(_tty_ch, TIOCSETP, &_tty))
  381. # define noecho()         (_tty.sg_flags &= ~ECHO,  \
  382.                             ioctl(_tty_ch, TIOCSETP, &_tty))
  383. #endif
  384.  
  385. #define SIZE         512
  386. #define CMASK         0377
  387. #define ESC            '\033'
  388.  
  389. static char recvbuf[SIZE];
  390. static char *progname;
  391. int debug;                    /* debug mode             */
  392. int aflag;                    /* alternate string     */
  393. int sflag;                    /* print strings        */
  394. int qflag;                    /* quiet mode             */
  395. int fflag;                    /* use strings file     */
  396.  
  397. int found = FALSE;
  398. int index = 0;
  399. int finish(), wakeup(), done();
  400.  
  401. char *decode();
  402.  
  403. jmp_buf env;
  404.  
  405. main(argc, argv)
  406. char *argv[];
  407. {
  408.     register int x;
  409.  
  410.     progname = argv[0];
  411.  
  412.     for (x = 1; x < argc; x++) {
  413.         if (argv[x][0] != '-')
  414.             break;
  415.         switch (argv[x][1]) {
  416.             case 'a':
  417.                 aflag = TRUE;
  418.                 break;
  419.             case 't':
  420.             case 's':
  421.                 sflag = TRUE;
  422.                 break;
  423.             case 'q':
  424.                 qflag = TRUE;
  425.                 break;
  426.             case 'f':
  427.                 fflag = TRUE;
  428.                 break;
  429.             case 'd':
  430.                 debug = TRUE;
  431.                 break;
  432.             default:
  433.                 usage();
  434.                 exit(1);
  435.         }
  436.     }
  437.  
  438.     setbuf(stdout, 0);
  439.     if(debug)
  440.         setbuf(stderr, 0);
  441.  
  442.     dprintf("[ %s debug mode enabled ]\n\n", progname);
  443.  
  444.     if(!isatty(0))
  445.         fprintf(stderr,"Not a tty.\n");
  446.  
  447. #ifdef USG5
  448.     if(ioctl(_tty_ch, TCGETA, &_otty) < 0)
  449. #else
  450.     if(ioctl(_tty_ch, TIOCGETP, &_tty) < 0)
  451. #endif
  452.     {
  453.         perror("gtty");
  454.         exit(1);
  455.     }
  456. #ifdef USG5
  457.     _ntty = _otty;
  458. #endif
  459.     if(crmode() < 0) {
  460.         perror("crmode");
  461.         exit(1);
  462.     }
  463.     if(noecho() < 0) {
  464.         perror("noecho");
  465.         exit(1);
  466.     }
  467.  
  468.     dprintf("[ initilizing term table... ]\n");
  469.     mktable();
  470.     dprintf("[ table done ]\n");
  471.  
  472.     if(!fflag) {
  473.         dointernal();
  474.     } else
  475.         dprintf("!fflag.  not doing dointernal().\n");
  476.  
  477.     index = tabmark;
  478.     dprintf("main: we'll do a dotab()\n");
  479.     dotab();
  480.     dprintf("main: dotab done\n");
  481.  
  482.     putc('\r', stderr);
  483.     (void) nocrmode();
  484.     (void) echo();
  485.     if(!found) {
  486.         dprintf("end of main\n");
  487.         notrecognized();
  488.     }
  489. }
  490.  
  491. done()
  492. {
  493.     putc('\r', stderr);
  494.     (void) nocrmode();
  495.     (void) echo();
  496.     exit(0);
  497. }
  498.  
  499. /*
  500.  * finish - clean things up.
  501.  */
  502. finish()
  503. {
  504.     dprintf("finish called\n");
  505.     putc('\r', stderr);
  506.     (void) nocrmode();
  507.     (void) echo();
  508.     if(recvbuf[0] != NULL)
  509.         (void) prinfo(compare(recvbuf, 0, tabtotal), 1);
  510.         
  511.     dprintf("finish done\n");
  512.     if(!found)
  513.         notrecognized();
  514.     exit(0);
  515. }
  516.  
  517. prinfo(t, what)
  518. struct qt *t;
  519. int what;
  520. {
  521.     int len = 0;
  522.     int st = FALSE;
  523.  
  524.     dprintf("prinfo startup\n");
  525.     if((t->qt_termname[0] != NULL) && (recvbuf[0] != NULL)) {
  526.         if(debug || sflag) {
  527.             len = strlen(recvbuf);
  528.             fprintf(stderr, "%s receives %d character%s:", 
  529.                 progname, len, (len == 1) ? "" : "s");
  530.             fprintf(stderr, " %s\n", decode(recvbuf));
  531.         }
  532.         if(!qflag)
  533.             if(t->qt_fullname[0] != NULL)
  534.                 fprintf(stderr, "Terminal recognized as %s (%s)\n", 
  535.                     t->qt_termname, t->qt_fullname);
  536.             else
  537.                 fprintf(stderr, "Terminal recognized as %s\n", 
  538.                     t->qt_termname);
  539.         printf("%s\n", t->qt_termname);
  540.         found = TRUE;
  541.         done();
  542.         /*NOTREACHED*/
  543.     } else {
  544.         found = FALSE;
  545.         if(what) {
  546.             dprintf("prinfo(): doing notrecognized()\n");
  547.             notrecognized();
  548.             done();
  549.             /*NOTREACHED*/
  550.         }
  551.     }
  552.     dprintf("prinfo done\n");
  553.     return(st);
  554. }
  555.  
  556. /*
  557.  * compare - actually compare what we received against the table.
  558.  */
  559. struct qt *
  560. compare(str, start, stop)
  561. char *str;
  562. int start;
  563. int stop;
  564. {
  565.     register int i = 0;
  566.     int len;
  567.  
  568.     dprintf("compare(%s, %d, %d) startup.\n", decode(str), start, stop);
  569.     alarm(0);
  570.  
  571.     i = start;
  572.     while(i <= stop) {
  573.         dprintf("compare(): tr = '%s'\n", decode(termtab[i].qt_recvstr));
  574.         if(strncmp(str, termtab[i].qt_recvstr, 
  575.           strlen(termtab[i].qt_recvstr)) == 0) {
  576.             found = TRUE;
  577.             return(&termtab[i]);
  578.         }
  579.         ++i;
  580.     }
  581.     found = FALSE;
  582. }
  583.  
  584. /*
  585.  * getch - read in a character at a time.
  586.  */
  587. getch()
  588. {
  589.     char c;
  590.  
  591.     (void) read(0, &c, 1);
  592.     return(c & CMASK);
  593. }
  594.  
  595. /*
  596.  * decode - print str in a readable fashion
  597.  */
  598. char *
  599. decode(str)
  600. char *str;
  601. {
  602.     char buf[BUFSIZ];
  603.     char tmp[10];
  604.  
  605.     strcpy(buf, "");
  606.     while(*str) {
  607.         if (*str == ESC) {
  608.             strcat(buf, "<esc> ");
  609.         } else if((*str <= 33) || (*str >= 127)) {
  610.             sprintf(tmp,"\\%o ", *str);
  611.             strcat(buf, tmp);
  612.         } else {
  613.             sprintf(tmp,"%c ", *str);
  614.             strcat(buf, tmp);
  615.         }
  616.         *++str;
  617.     }
  618.     return(buf);
  619. }
  620.  
  621. usage()
  622. {
  623.     fprintf(stderr, "usage: %s [ -asq ]\n", progname);
  624. }
  625.  
  626. mktable()
  627. {
  628.     register int i, z;
  629.     FILE *fd, *fopen();
  630.     char file[BUFSIZ];
  631.     char buf[BUFSIZ];
  632.     char lbuf[4][BUFSIZ];
  633.     char *home, *msg, *fixctl();
  634.     int iserr = 0;
  635.     extern char *terms[];
  636.     struct passwd *pwd;
  637.  
  638.     i = z = 0;
  639.     /*
  640.      * Copy internal table
  641.      */
  642.     while(terms[z] != NULL && i < MAXTERMS) {
  643.         (void) strcpy(termtab[i].qt_sendstr, (aflag) ? ALTSEND : SEND);
  644.         (void) strcpy(termtab[i].qt_recvstr, terms[z + T_STR]);
  645.         (void) strcpy(termtab[i].qt_termname, terms[z + T_NAME]);
  646.         (void) strcpy(termtab[i].qt_fullname, terms[z + T_LNAME]);
  647.  
  648.         z += 3;
  649.         ++i;
  650.     }
  651.     tabmark = i;
  652.  
  653.     /*
  654.      * Try and read the user's own table
  655.      */
  656.     if((home = (char *) getenv("HOME")) == NULL) {
  657.         if((pwd = (struct passwd *) getpwuid(getuid())) == NULL) {
  658.             fprintf(stderr, "Who the hell are you????\n");
  659.             exit(1);
  660.         }
  661.         home = pwd->pw_dir;
  662.     }
  663.     dprintf("home = '%s'\n", home);
  664.     sprintf(file, "%s/%s", home, STRFILE);
  665.     dprintf("strfile = '%s'\n", file);
  666.     if(fflag && (fd = fopen(file, "r")) != NULL) {
  667.         while(fgets(buf, sizeof(buf), fd) && i < MAXTERMS) {
  668.             if(buf[0] == '#' || buf[0] == '\n')
  669.                 continue;
  670.  
  671.             lbuf[0][0] = NULL;
  672.             lbuf[1][0] = NULL;
  673.             lbuf[2][0] = NULL;
  674.             lbuf[3][0] = NULL;
  675.     
  676.             (void) sscanf(buf, "%s%s%s\t%[^\n]", 
  677.                 lbuf[0], lbuf[1], lbuf[2], lbuf[3]);
  678.             if(lbuf[0][0] == NULL)
  679.                 continue;
  680.             if(lbuf[1][0] == NULL) {
  681.                 iserr = TRUE;
  682.                 msg = "receive string";
  683.             }
  684.             if(lbuf[2][0] == NULL) {
  685.                 iserr = TRUE;
  686.                 msg = "terminal name";
  687.             }
  688.             if(iserr) {
  689.                 fprintf(stderr, "%s: Error parsing %s.\n", file, msg);
  690.                 exit(1);
  691.             }
  692.             (void) strcpy(termtab[i].qt_sendstr, fixctl(lbuf[0]));
  693.             (void) strcpy(termtab[i].qt_recvstr, fixctl(lbuf[1]));
  694.             (void) strcpy(termtab[i].qt_termname, lbuf[2]);
  695.             (void) strcpy(termtab[i].qt_fullname, lbuf[3]);
  696.  
  697.             dprintf("entry %d:\n", i);
  698.             dprintf("qt_sendstr = %s\n", decode(termtab[i].qt_sendstr));
  699.             dprintf("qt_recvstr = %s\n", decode(termtab[i].qt_recvstr));
  700.             dprintf("qt_termname = '%s'\n", termtab[i].qt_termname);
  701.             dprintf("qt_fullname = '%s'\n", termtab[i].qt_fullname);
  702.  
  703.             ++i;
  704.         }
  705.     }
  706.     tabtotal = i;
  707.     dprintf("termtab total  = %d\n", tabtotal);
  708.     dprintf("termtab mark  = %d\n", tabmark);
  709. }
  710.  
  711. listen(q)
  712. struct qt *q;
  713. {
  714.     register int i;
  715.     register char c;
  716.     char end, begin;
  717.  
  718.     dprintf("listen startup\n");
  719.     alarm(0);
  720.  
  721.     dprintf("listen: listening for '%s'\n", decode(q->qt_recvstr));
  722.  
  723.     if (q->qt_recvstr[0] == NULL) {
  724.         begin = ESC;
  725.         end = 'c';
  726.     } else {
  727.         begin = q->qt_recvstr[0];
  728.         end = q->qt_recvstr[strlen(q->qt_recvstr)-1];
  729.     }
  730.  
  731.     dprintf("listen: read initial character...\n");
  732.     if(setjmp(env)) {
  733.         dprintf("listen: setjmp TRUE\n");
  734.         if(found)
  735.             done();
  736.         ++index;
  737.         (void) fflush(stdin);
  738.         dprintf("listen: dotab()\n");
  739.         dotab();
  740.     } else {
  741.         dprintf("listen: setjmp FALSE...set alarm\n");
  742.         signal(SIGALRM, wakeup);
  743.         alarm(3);
  744.         dprintf("listen: read char\n");
  745.         recvbuf[0] = getch();
  746.         alarm(0);
  747.         dprintf("recvbuf[0] = '\\%o'\n", recvbuf[0]);
  748.  
  749.     }
  750.     i = 0;
  751.     if(recvbuf[0] == begin) {
  752.         dprintf("listen begin\n");
  753.         while(c != end) {
  754.             if(setjmp(env))  {
  755.                 dprintf("listen: setjmp (2) return\n");
  756.                 return;
  757.             } else {
  758.                 signal(SIGALRM, wakeup);
  759.                 alarm(2);
  760.                 dprintf("listen: read (2) char\n");
  761.                 c = getch();
  762.                 alarm(0);
  763.                 dprintf("recvbuf[0] = '\\%o'\n", recvbuf[0]);
  764.             }
  765.             recvbuf[++i] = c;
  766.         }
  767.         if(debug)
  768.             fprintf(stderr,"\n[ Received terminator. ]\n");
  769.     } else {
  770.         dprintf("listen: Not Recognized.  exiting...\n");
  771.         notrecognized();
  772.         putc('\r',stderr);
  773.         (void) nocrmode();
  774.         (void) echo();
  775.         exit(1);
  776.     }
  777.     dprintf("listen done\n");
  778. }
  779.  
  780. notrecognized()
  781. {
  782.     if(!qflag)
  783.         fprintf(stderr, 
  784.           "Terminal NOT recognized - defaults to \"dumb\".\n");
  785.     puts("dumb");
  786. }
  787.  
  788. wakeup()
  789. {
  790.     dprintf("wakeup called\n");
  791.     longjmp(env, 1);
  792.     dprintf("wakeUP: done\n");
  793. }
  794.  
  795. dotab()
  796. {
  797.     int wakeup();
  798.     int st = FALSE;
  799.     static int firsttime = TRUE;
  800.  
  801.     dprintf("dotab startup\n");
  802.     dprintf("index = %d\n", index);
  803.     if(index > tabtotal) {
  804.         /*
  805.          * if we haven't reset things yet, do so.
  806.          * now try the internal tables if the user's
  807.          * tables failed.
  808.          */
  809.         if(!has_set)  {
  810.             tabtotal = tabmark;
  811.             index = 0;
  812.             has_set = 1;
  813.             dprintf("dotab(): has_set now true.\n");
  814.             dotab();
  815.         }
  816.         dprintf("dotab(): index > tabtotal\n");
  817.         finish();
  818.     }
  819.     if(!found || fflag) {
  820.         while(!found && termtab[index].qt_sendstr[0] != NULL && !st) {
  821.             dprintf("dotab: termtab PASS %d\n", index);
  822.             dprintf("dotab: sending str %s\n", 
  823.                 decode(termtab[index].qt_sendstr));
  824.             (void) fflush(stdin);
  825.             if(firsttime || strncmp(termtab[index].qt_sendstr, 
  826.               termtab[index-1].qt_sendstr,
  827.               strlen(termtab[index].qt_sendstr))) {
  828.                 firsttime = FALSE;
  829.                 dprintf("dotab(): sendstr's didn't match.\n");
  830.                 dprintf("dotab: str1 %s\n", 
  831.                     decode(termtab[index].qt_sendstr));
  832.                 dprintf("dotab: str2 %s\n", 
  833.                     decode(termtab[index-1].qt_sendstr));
  834.                 fprintf(stderr, termtab[index].qt_sendstr);
  835.                 (void) fflush(stdout);
  836.                 (void) fflush(stderr);
  837.                 (void) listen(&termtab[index]);
  838.             } else {
  839.                 dprintf("dotab(): sendstr's DID match.  No str sent.\n");
  840.                 dprintf("dotab: str1 %s\n", 
  841.                     decode(termtab[index].qt_sendstr));
  842.                 dprintf("dotab: str2 %s\n", 
  843.                     decode(termtab[index-1].qt_sendstr));
  844.             }
  845.  
  846.             firsttime = FALSE;
  847.             dprintf("dotab(): recbuf = '%s'\n", decode(recvbuf));
  848.             dprintf("dotab(): qt_rec = '%s'\n", 
  849.                 decode(termtab[index].qt_recvstr));
  850.             st = prinfo(compare(recvbuf, tabmark, tabtotal), !fflag);
  851.             dprintf("st = %d\n", st);
  852.             ++index;
  853.         }
  854.         dprintf("dotab(): mark 1\n");
  855.     }
  856.     dprintf("i'm here (2)\n");
  857.     if(!found) {
  858.         dprintf("end of dotab\n");
  859.         dointernal();
  860.         if(!found) {
  861.             dprintf("dotab: dointernal failed.\n");
  862.             notrecognized();
  863.         }
  864.     }
  865.     done();
  866. }
  867.  
  868. dointernal()
  869. {
  870.     struct qt q;
  871.  
  872.     dprintf("DOINTERNAL startup.\n");
  873.  
  874.     (void) fflush(stdin);
  875.     fprintf(stderr, (aflag) ? ALTSEND : SEND);
  876.     (void) fflush(stdout);
  877.     (void) fflush(stderr);
  878.  
  879.     q.qt_recvstr[0] = NULL;
  880.  
  881.     (void) listen(&q);
  882.  
  883.     (void) prinfo(compare(recvbuf, 0, tabmark), 1);
  884.     if(found)
  885.         done();
  886.  
  887.     dprintf("dointernal end.\n");
  888. }
  889.  
  890. char *
  891. fixctl(str)
  892. char *str;
  893. {
  894.     register int i;
  895.     char buf[BUFSIZ];
  896.  
  897.     i = 0;
  898.     while(*str) {
  899.         if(*str == '^')
  900.             buf[i++] = *++str & 037;
  901.         else
  902.             buf[i++] = *str;
  903.         *++str;
  904.     }
  905.     buf[i] = NULL;
  906.     return(buf);
  907. }
  908. SHAR_EOF
  909. echo shar: extracting "'qterm.1'" '(3334 characters)'
  910. if test -f 'qterm.1'
  911. then
  912.     echo shar: over-writing existing file "'qterm.1'"
  913. fi
  914. cat << \SHAR_EOF > 'qterm.1'
  915. .\"
  916. .\" $Header: qterm.1,v 1.1 86/12/22 10:45:25 mcooper Exp $
  917. .\"
  918. .TH QTERM 1 8/8/86
  919. .ds ]W USC Computing Services
  920. .SH NAME
  921. qterm \- Query Terminal
  922. .SH SYNOPSIS
  923. qterm 
  924. [
  925. .B \-a
  926. ]
  927. [
  928. .B \-f
  929. ]
  930. [
  931. .B \-s
  932. ]
  933. [
  934. .B \-q
  935. ]
  936. .SH DESCRIPTION
  937. .I Qterm
  938. is used to query a terminal to determine its name.
  939. This is done by sending the fairly universal 
  940. string ``<ESCAPE>Z'' to the terminal,
  941. reading in a response, and comparing it against a master table of possible
  942. responses.
  943. The ``name'' printed to standard output should be one found in
  944. the
  945. .I termcap(5) 
  946. database.
  947. .PP
  948. For 
  949. .I csh(1) 
  950. users,
  951. putting a line in your 
  952. .I .login 
  953. file such as:
  954. .sp 1
  955. .in +.5i
  956. setenv TERM `qterm`
  957. .in -.5i
  958. .sp 1
  959. should automagically set your terminal type.
  960. For 
  961. .I sh(1)
  962. users, putting these lines in your 
  963. .I .profile 
  964. file should set your terminal type:
  965. .sp 1
  966. .in +.5i
  967. TERM=`qterm`
  968. .br
  969. export TERM
  970. .in -.5i
  971. .sp 1
  972. .SH OPTIONS
  973. .IP \-a
  974. Use the alternate string ``<ESCAPE>[c'' when asking the terminal to
  975. identify itself.  This string is recognized by most ANSI compatible
  976. terminals.
  977. .IP \-f
  978. If the file
  979. .B $HOME/.qterm
  980. is present, it's contents are scanned to produce information for
  981. querying terminals.  In this way, a user may setup different values
  982. for certain terminals.
  983. After the contents of this file have been scanned, 
  984. .I qterm
  985. proceeds to query the terminal with the information provided
  986. in the file
  987. .B $HOME/.qterm.
  988. If an un-intelligable response is received (or non at all), 
  989. .I qterm
  990. will proceed to use its own internal information to determine the terminal
  991. type.
  992. .IP \-s
  993. Display the response received from
  994. the terminal in a ``nice'' fashion.
  995. .IP \-q
  996. Be ``quiet'' and only print the terminal name to standard
  997. output.
  998. .SH ".QTERM FILE"
  999. .PP
  1000. The format of the file
  1001. $HOME/.qterm
  1002. consists of four fields each seperated by white space (tabs and/or spaces).
  1003. The first field is the string that should be used to query the terminal.
  1004. The second field is the string to expect in response to the query.
  1005. The third field is the terminal name (compatible with 
  1006. .I termcap(5))
  1007. to print to standard output.
  1008. The fourth field is optional and may contain a description of the exact
  1009. manufacturer and model name of the terminal to be used in a message
  1010. printed to standard error.
  1011. .PP
  1012. Blank lines or lines starting with the character ``#''
  1013. are ignored and may be used as comment lines.
  1014. A character preceeded by a ``^'' is taken to mean the 
  1015. .I control
  1016. character.  (i.e. ``^['' is interpretted as an <ESCAPE>).
  1017. .PP
  1018. Below is a sample file:
  1019. .sp 2
  1020. .nf
  1021.     #
  1022.     # QTerm File
  1023.     #
  1024.     ^[Z\0\0\0\0\0^[[?1;1c\0\0\0\0\0vt100\0\0\0\0\0A vt100 with STP
  1025.     ^[Z\0\0\0\0\0^[[?1;2c\0\0\0\0\0vt100\0\0\0\0\0ANSI/VT100 Clone
  1026.     ^[Z\0\0\0\0\0^[[?1;3c\0\0\0\0\0vt100\0\0\0\0\0A vt100 with AVO and STP
  1027.     ^[Z\0\0\0\0\0^[[?1;4c\0\0\0\0\0vt100\0\0\0\0\0A vt100 with GPO
  1028.     ^[Z\0\0\0\0\0^[iBO\0\0\0\0\0\0\0\0z29\0\0\0\0\0\0\0Zenith in Zenith Mode
  1029. .fi
  1030. .sp
  1031. .SH AUTHOR
  1032. Michael A. Cooper, 
  1033. .br
  1034. USC Computing Services, Los Angeles.
  1035. .SH FILES
  1036. /etc/termcap    \- termcap(5) database
  1037. .SH SEE ALSO
  1038. csh(1), sh(1), termcap(5)
  1039. .SH DIAGNOSTICS
  1040. .IP "\fITerminal not recognized - defaults to dumb.\fP"
  1041. .I QTerm
  1042. did not receive a response from the terminal, or the response
  1043. did not match any that 
  1044. .I qterm 
  1045. has stored internally.  Use the \-s option to check to see which
  1046. is the case.
  1047. .SH BUGS
  1048. Many terminals do not send a response at all.
  1049. SHAR_EOF
  1050. #    End of shell archive
  1051. exit 0
  1052. -- 
  1053. Michael A. Cooper, University Computing Services, U of Southern California
  1054.   UUCP: {sdcrdcf, uscvax}!usc-oberon!mcooper  BITNET: mcooper@uscvaxq
  1055.   ARPA: mcooper@usc-oberon.USC.EDU            PHONE: (213) 743-3462
  1056.  
  1057.